# PixelPet

[![build](https://github.com/Prof9/PixelPet/actions/workflows/build.yaml/badge.svg)](https://github.com/Prof9/PixelPet/actions)

PixelPet is an image processing tool for retro games modding. It allows you to automatize converting common image files (such as PNG) to the binary formats supported by retro consoles. You can also go the other way, using PixelPet to extract and render binary images from game ROMs.

At the moment, PixelPet is geared mostly towards the Game Boy Advance and Nintendo DS family of systems, but should be easy to extend to other systems.

Note that PixelPet is a work-in-progress, and new features and functionality are added as the need for them arises. As such, the information described below is subject to change.

## Workbench

Internally PixelPet has a "workbench" that holds the main objects that it's processing on. Each of the commands supported by PixelPet operates on one or more of these objects. In this sense, PixelPet mimics the video system used by retro consoles.

The objects held by the workbench include:

 *  Set of palettes.
 *  Bitmap image.
 *  Stream of bytes.
 *  Tileset.
 *  Tilemap.

For instance, the loaded bitmap image can be converted to a combination of tileset + tilemap, which can then be output to a bytestream. Or vice versa, a tileset and tilemap can be read from a bytestream, then used to render a new bitmap image.

### Palettes

Every palette in PixelPet is assigned a unique palette slot number. Whenever a new palette is added, it gets the lowest unclaimed palette slot number (starting at 0), but it is also possible to manually specify the palette slot for each palette. With this mechanism, PixelPet fully supports generating and rendering multi-palette tilesets and tilemaps.

A palette can hold any number of colors, but a palette may have a maximum number of colors set; if you attempt to add any colors beyond the maximum, an error is thrown. The colors can be in any of the supported formats, such as 24-bit and 15-bit, and can be converted between formats with certain commands.

### Bitmap

The bitmap is simply a full image that is being operated on. Internally this is an array of integers, one per pixel. The bitmap can be imported from various file formats; this has not been extensively tested, however, so using standard PNG images in 24-bit RGB or 32-bit RGBA format is advised. You can also export the bitmap to a standard PNG image file.

### Bytestream

The bytestream is a sequence of bytes that any of the other objects in the workbench can be serialized to, or deserialized from. It can also be imported from or written to a binary file.

### Tileset

The tileset holds a set of tiles that can be used in conjunction with the tilemap to represent an image. Each tileset has a specific tile size as well as a color format. By default, the tileset has a tile size of 8 by 8 pixels, and uses a 32-RGBA color format.

Whenever a tile is added to the tileset, PixelPet will first check whether that tile already exists in the tileset, either as-is, or flipped in the horizontal or vertical direction, or both. If this is the case, then the tile will not be added to the tileset. However, it is possible to disable this behavior if you want to purposely add duplicate tiles to the tileset.

The tileset may be unindexed, meaning each pixel value in each tile holds the actual color value that will be displayed, or it may be indexed, meaning each pixel value represents an index in a palette, and the color value that is located in the palette at that index will be displayed instead.

### Tilemap

The tilemap holds a set of tile display entries, that can be used in conjunction with the tileset to represent an image. Each tile display entry holds the number of the tile, whether the tile should be flipped horizontally and/or vertically, and which palette slot should be used to render the tile (in case the tileset is indexed).

In PixelPet, the tilemap does not have a specific predefined width or height (i.e. number of tiles per row/column). Instead, tile entries can be added onto the tilemap indefinitely, and the tilemap may then be rendered at various specific widths and heights.

## Color formats

PixelPet currently supports the following color formats. A color format describes the range of each color component (Red, Green, Blue, and optionally, Alpha), and how these are stored in memory. Names of color formats follow *word order*, e.g. BGR555 is a format where the Blue component is stored in the upper bits and the Red component is stored in the lower bits.

 *  **2BPP** - General 2-bit grayscale, where `0x0` is pure black and `0x3` is pure white.
 *  **4BPP** - General 4-bit grayscale, where `0x0` is pure black and `0xF` is pure white.
 *  **8BPP** - General 8-bit grayscale, where `0x00` is pure black and `0xFF` is pure white.
 *  **GB** - 2-bit grayscale as it is used on the Game Boy, where the luminance is inverted. `0x0` is pure white, and `0x3` is pure black.
 *  **GBA** / **BGR555** - 15-bit color as it is used on the Game Boy Advance, where the Red, Green and Blue components are all 5 bits. `0x0000` is pure black, and `0x7FFF` is pure white.
 *  **NDS** / **ABGR5551** - 16-bit color as it is used on the Nintendo DS, where the Red, Green and Blue components are 5 bits, and the Alpha component is 1 bit. `0x8000` is pure black, and `0xFFFF` is pure white.
 *  **24BPP** / **RGB888** - General 24-bit color, where the Red, Green and Blue components are all 8 bits. `0x000000` is pure black, and `0xFFFFFF` is pure white.
 *  **32BPP** / **ARGB8888** - General 32-bit color, where the Red, Green, Blue and Alpha components are all 8 bits. `0xFF000000` is pure black, and `0xFFFFFFFF` is pure white.
 *  **RGB555** - 15-bit color where the Red, Green and Blue components are all 5 bits. `0x0000` is pure black, and `0x7FFF` is pure white. Here the Blue component occupies the low bits and the Red component occupies the high bits.

## Tilemap formats

PixelPet currently supports the following tilemap formats. A tilemap format contains information about how the tilemap (and by extension, the tileset) is stored. It describes the tile size; whether the image is indexed (meaning a palette is needed to proper display it); the color format used for tiles; how tilemap entries are stored in memory; and the capabilities of the platform (e.g. whether flipping tiles is allowed).

 *  **GB** - 2 bits per pixel tilemap format as it used on the Game Boy, where a pair of 2 bytes collectively holds 8 pixels.
 *  **GBA-4BPP** / **NDS-4BPP** - 4 bits per pixel tilemap format as it is used on the Game Boy Advance and Nintendo DS. This tilemap format uses indexed colors, meaning a palette is required to properly display it. If no suitable palette is loaded, any rendered tiles will be rendered using the general `4BPP` grayscale color format instead.
 *  **GBA-8BPP** / **NDS-8BPP** - 8 bits per pixel tilemap format as it is used on the Game Boy Advance and Nintendo DS. This tilemap format uses indexed colors, meaning a palette is required to properly display it. If no suitable palette is loaded, any rendered tiles will be rendered using the general `8BPP` grayscale color format instead.

## Usage

PixelPet currently supports the following commands. Each command is specified as a separate command-line argument, followed by its parameters, also as command-line arguments. For example, to load an input image `input.png` and then store it elsewhere as `output.png`, you would run the following command from your favorite console:

```
PixelPet Import-Bitmap "input.png" Export-Bitmap "output.png"
```

Alternatively, you can also place the following in a basic text file `script.txt` (any extension may be used):

```
Import-Bitmap "input.png"
Export-Bitmap "output.png"
```

Then, run the script from your console as follows:

```
PixelPet Run-Script "script.txt"
```

## Commands

### Help
```
Help
```

Prints the list of commands supported by PixelPet along with their parameters.

### Run-Script
```
Run-Script <path> [--recursive/-r]
```

Runs the script from the basic text file specified by `<path>`. Said script can also include further `Run-Script` commands to run even more scripts from different files.

By default it is not allowed to recursively include any scripts that are already on the current stack. For instance, if a script named `script.txt` contains the command `Run-Script script.txt`, then an error is thrown. Moreover, if `script1.txt` calls `script2.txt`, which then calls `script1.txt` again, an error is thrown as well. However, this restriction can be disabled by specifying the `--recursive` or `-r` flag.

**Example usage:**
```
Run-Script "script.txt"
```

### Set-Variable
```
Set-Variable <name> <value>
```

Sets the variable with name `<name>` to string `<value>`. If the variable does not exist, it is created. The `<name>` may consist only of alphanumerical characters and underscores (`[A-Za-z0-9_]`).

After setting a variable, you can use it in any other command (including another `Set-Variable`) by writing the name of variable surrounded with `<>`. If you pass a parameter containing variable(s) to a command, any variables in the parameter are expanded before the command is executed. Expansion is done by replacing any instance of `<var>`, where `var` is the name of a variable, with the string value of that variable. It is possible to nest parameters, e.g. `<var1<var2>>`.

When using the `Run-Script` command, all variables are passed to the script as well.

**Example usage:**
```
Set-Variable map_top "map-top.png"
Set-Variable map_bottom "map-bottom.png"
Set-Variable layer "top"
Import-Bitmap "<map_<layer>>"
```

Imports the image `map-top.png` to the workbench.

### Import-Bitmap
```
Import-Bitmap <path> [--format/-f <format>]
```

Imports the image file specified by `<path>` to the workbench bitmap. The previous workbench bitmap is discarded. Using standard 24-bit or 32-bit PNG images is advised.

If the `--format` option is not present, all pixels in the bitmap will be imported as-is. If it is present, all pixels in the bitmap will be interpreted as if they were in the specified color format.

**Example usage:**

```
Import-Bitmap "input.png"
```
Imports the image `input.png` to the workbench.

### Export-Bitmap
```
Export-Bitmap <path> [--format/-f <format>]
```

Exports the workbench bitmap to the file specified by `<path>`. The output bitmap is always stored as a 32-bit image.

If the `--format` option is not present, all pixels in the bitmap are converted to 32-bit color during export (this does not modify the workbench bitmap). If it is present, the pixels are converted to the given format. Note that since the image itself is stored in 32-bit format, this means the image won't display correctly, but it can be a more convenient way to check color values than exporting to bytes and checking with a hex editor.

However, if the chosen color format for `--format` does not contain an alpha channel, `Export-Bitmap` will set the 32-bit alpha channel of all pixels to 255 after conversion.

**Example usage:**
```
Export-Bitmap "output.png"
```
Exports the bitmap in the workbench to `output.png`.

### Import-Bytes
```
Import-Bytes <path> [--append/-a] [--offset/-o <count>] [--length/-l <count>]
```

Imports the binary file specified by `<path>` to the workbench bytestream. If `--append` is present, then the binary file is appended to the previous  workbench bytestream; otherwise, the previous workbench bytestream is discarded.

Optionally, you can use the `--offset` and/or `--length` parameters to specify the offset in the file from which bytes should be read (by default, this is 0), and/or the maximum number of bytes that should be loaded (by default, this is unbounded). Bytes will be loaded until the end of the file or the maximum length is reached, whichever comes first.

**Example usage:**
```
Import-Bytes "input.bin" --offset 0x4 --length 0x20
```
Imports `32 (0x20)` bytes from file `input.bin` starting at offset `4 (0x4)`.

### Export-Bytes
```
Export-Bytes <path>
```

Exports the entire workbench bytestream to the file specified by `<path>`.

**Example usage:**
```
Export-Bytes "output.bin"
```
Exports the workbench bytestream to `output.bin`.

### Clear-Palettes
```
Clear-Palettes
```

Discards all workbench palettes.

### Clear-Tileset
```
Clear-Tileset [--tile-size/-s <width> <height>]
```

Discards the workbench tileset, and initializes a new one. Optionally, the `--tile-size` parameter can be used to specify the tile width and height (in pixels) for the new tileset. By default, this is 8 by 8 pixels.

```
Clear-Tileset --tile-size 16 16
```
Initializes a new tileset with tile size 16 by 16 pixels.

### Clear-Tilemap
```
Clear-Tilemap
```

Discards the workbench tilemap, and initializes a new one.

### Extract-Palettes
```
Extract-Palettes [--append/-a] [--palette-number/-pn <number>] [--palette-size/-ps <count>] [--palette-count/-pc <count>] [--x/-x <pixels>] [--y/-y <pixels>] [--width/-w <pixels>] [--height/-h <pixels>] [--tile-size/-s <width> <height>]
```

Extracts palettes from the workbench bitmap.

This is done by first splitting the bitmap into tiles. For each tile, we then take the color values present and add these to one of the existing palettes (removing any duplicate colors) if possible, or add a new palette if this does not fit in any of the current palettes.

PixelPet attempts to minimize the number of palettes used, but a greedy algorithm is used, so it is not guaranteed that this does lead to the minimum number of palettes. If this is a concern, it may be better to create the templates manually and load them via the `Read-Palettes` command instead.

If `--append` is present, then the extracted palettes are added to the current workbench palettes. Otherwise, the current workbench palettes are discarded first.

The `--palette-number` option can be used to specify the initial palette slot number that will be used for any newly created palette. This slot number is increased until an empty slot is found. If this option is not specified, new palettes will get the highest slot number among the loaded palettes + 1.

The `--palette-size` option can be used to specify a maximum palette size for any newly create palette. Palettes that were created before this command is run retain their original maximum palette size. By default, the maximum palette size is unbounded.

The `--palette-count` option can be used to specify the maximum number of palettes that may be added. If the bitmap requires more palettes, then an error is thrown. By default, the maximum number of palettes that may be added is unbounded.

The `--x`, `--y`, `--width` and `--height` options can be used to process only a portion of the workbench bitmap. The workbench bitmap will not be changed, but it will be processed as if it was cropped using the given parameters, and the first tile begins in the top left corner of the cropped bitmap. By default, the entire workbench bitmap is processed.

The `--tile-size` option specifies the size of each tile in pixels. If this option is omitted, then tile size of the current workbench tileset is used. As a special case, when a width and/or height of 0 is specified for `--tile-size`, it will use the width and/or height of the entire workbench bitmap, so e.g. `--tile-size 0 0` will treat the entire bitmap as a single "tile".

**Example usage:**
```
Import-Bitmap "input.png"
Extract-Palettes --palette-size 16
```
Extracts 16-color palettes from the workbench bitmap.

### Read-Palettes
```
Read-Palettes [--append/-a] [--palette-number/-pn <number>] [--palette-size/-ps <count>] [--x/-x <pixels>] [--y/-y <pixels>] [--width/-w <pixels>] [--height/-h <pixels>]
```

Reads a palettes from a *palette image* loaded into the workbench bitmap. The colors read from the palette image are loaded into new palette(s).

This command can be used to load a predefined set of palettes. The palettes are stored as a *palette image*; an image consisting of 8 by 8 pixel blocks of a solid color, where each block represents one color in the palette. For example, a palette with 16 colors can be represented as a 128 by 8 pixels palette image. The blocks are read left-to-right, top-to-bottom. If any 8 by 8 pixel block does not consist solely of pixels with the exact same color value, an error will be thrown.

This command differs from `Extract-Palettes` in that the user specifies the palette explicitly; this allows for e.g. duplicate colors to be added, which would be removed if `Extract-Palettes` is used.

If `--append` is present, then the read palettes are added to the current workbench palettes. Otherwise, the current workbench palettes are discarded first.

The `--palette-number` option can be used to specify the initial palette slot number that will be used for any newly created palette. This slot number is increased until an empty slot is found. If this option is not specified, new palettes will get the highest slot number among the loaded palettes + 1.

The `--palette-size` option can be used to specify the maximum palette size for the newly created palettes. Once the maximum size for the current palette is reached, a new palette is added. As such, by using the `--palette-size` option, multiple palettes can be read at once. If the `--palette-size` option is not used, all colors will be placed into a single, unbounded palette.

The `--x`, `--y`, `--width` and `--height` options can be used to process only a portion of the workbench bitmap. The workbench bitmap will not be changed, but it will be processed as if it was cropped using the given parameters, and the first tile begins in the top left corner of the cropped bitmap. By default, the entire workbench bitmap is processed.

**Example usage:**
```
Import-Bitmap "128x16.png"
Read-Palettes --palette-size 16
```
Imports a 128 by 16 pixels palette image representing 2 palettes of 16 colors. Then, reads the 2 palettes from the palette image.

### Render-Palettes
```
Render-Palettes [--colors-per-row/-cw <count>]
```

Renders the workbench palettes as a *palette image*, and writes this to the workbench bitmap. The old workbench bitmap is discarded. This is the same sort of palette image as is used for the `Read-Palettes` command. Each loaded palette is placed on a separate row, with each color rendered as an 8-by-8 pixels square.. The palette image is converted/rendered in 32-bit color.

The `--colors-per-row` option can be used to specify the number of colors that are rendered per row. If there are more colors than fit on the row, then the colors wrap around to the next row. If the end of a palette is reached, but there is still room on the current row, then PixelPet moves on to the next row regardless and leaves the remainder of the current row empty. This option can be used e.g. to render a 256-color palette as a 16-by-16 color palette image rather than a 256-by-1 color palette image. If the `--colors-per-row` option is not specified, the palette image will use the width of the largest palette.

**Example usage:**
```
Import-Bitmap "input-16-color.png"
Extract-Palettes --palette-size 16
Render-Palettes
Export-Bitmap "palette.png"
```
Imports a 16-color image, generates a 16-color palette from it, renders this palette as a palette image, and then writes this palette image to `palette.png`.

### Render-Tileset
```
Render-Tileset [--tiles-per-row/-tw <count>] [--format/-f <format>]
```

Renders the workbench tileset as an image, and writes this to the workbench bitmap. The old workbench bitmap is discarded.

If the workbench tileset uses indexed colors, then the workbench palettes are used when rendering the tiles. If there is a palette loaded with the same slot number as the palette that was originally used to index the tile, then that palette is used to render the tile. If there is no longer a palette loaded with that slot number, then the first palette that is currently loaded is used. Otherwise, if there are no palettes loaded at all, the tile is rendered using a generic grayscale palette.

If the workbench tileset does not used indexed colors, then each pixel is rendered as-is.

The `--tiles-per-row` option can be used to specify how many tiles should be rendered per row. By default, this is 32 tiles. For a tileset using 8 by 8 pixel tiles, this results in a tileset image that is 256 pixels wide. The height of the tileset image is computed automatically.

If the `--format` option is present, the tileset image is rendered using the specified color format; otherwise it is rendered in 32-bit color.

**Example usage:**
```
Import-Bitmap "input.png"
Extract-Palettes
Generate-Tilemap GBA-4BPP
Render-Tileset --tiles-per-row 16
Export-Bitmap "tileset.png"
```
Imports an image, generates a palette from it, generates a tilemap+tileset. Renders this tileset as an image with 16 tiles per row, and then writes this rendered tileset to `tileset.png`.

### Render-Tilemap
```
Render-Tilemap <tiles-per-row> <tiles-per-column>
```

Renders the workbench tilemap + tileset together as an image, and writes this to the workbench bitmap. The old workbench bitmap is discarded. The tilemap is rendered in 32-bit color.

Unlike the `Render-Tileset` command, both `<tiles-per-row>` and `<tiles-per-column>` must be specified. These indicate the number of tiles per row and column that will be rendered. For example, `Render-Tilemap 30 20` with 8 by 8 pixel tiles results in a bitmap of 240 by 160 pixels.

The tile entries in the tilemap are rendered left-to-right, top-to-bottom.

**Example usage:**
``` 
Import-Bytes "tilemap.bin"
Deserialize-Tilemap
Import-Bytes "tileset.bin"
Deserialize-Tileset GBA-4BPP
Render-Tilemap 30 20
Export-Bitmap "tilemap.png"
```
Imports and deserializes a tilemap and tileset from binary files. Then, renders the tilemap + tileset to a 240 by 160 pixel image, and then writes this rendered tilemap to `tilemap.png`.

### Crop-Bitmap
```
Crop-Bitmap [--x/-x <pixels>] [--y/-y <pixels>] [--width/-w <pixels>] [--height/-h <pixels>]
```

Crops the workbench bitmap using the specified parameters. The `--x` and `--y` options specify the x- and y-offset of the left and top edges respectively, whereas the `--width` and `--height` options specify the new width and height of the bitmap respectively. If any of the specified parameters fall outside the range of the original bitmap, they will be automatically adjusted to the bounds of the bitmap.

**Example usage:**
```
Crop-Bitmap --width 32 --height 32
```
Crops the workbench bitmap to the top-left 32 by 32 pixels.

### Convert-Bitmap
```
Convert-Bitmap <format> [--sloppy/-s]
```

Converts the workbench bitmap to the specified color format.

By default, most command produce a workbench bitmap that uses 32-bit color. Before the bitmap can be further processed for display on a retro console's display, usually, it must be converted to the proper color format first.

For every pixel in the bitmap, the Red, Green, Blue and Alpha components of each color value are scaled as follows:

```
out = (in + (in_max / 2) * out_max) / in_max
```
Where each division floors the result.

This is roughly equivalent to the following:
```
out = in * out_max / in_max
```
Where each division applies rounding in the correct direction.

For example, converting a 5-bit color component `31` to an 8-bit color component goes as follows:
```
31 * 255 / 31 = 255
```

However, many emulators and other image processing tools instead use an incorrect color scaling algorithm, where the color component is simply left-shifted, and the added bits are simply filled with zeroes. For example, again converting 5-bit color component `31` to 8-bit, the conversion is performed as follows:
```
31 << 3 = 248
```

Or, vice versa:
```
248 >> 3 = 31
```

By specifying the `--sloppy` option, PixelPet can use this bit-shift color scaling algorithm instead. This can be used to process images that have been ripped from inaccurate emulators.

**Example usage:**
```
Import-Bitmap "input.png"
Convert-Bitmap GBA --sloppy
Convert-Bitmap 32BPP
Export-Bitmap "output.png"
```
This loads a 32-bit image `input.png` which has been ripped from an inaccurate emulator, converts it back to its original GBA color format with the `--sloppy` option, and then converts it back to a 32-bit image using proper color scaling; effectively "fixing" the image. The fixed image is then written to `output.png`.

### Convert-Palettes
```
Convert-Palettes <format> [--sloppy/-s]
```

Converts all workbench palettes from their current color format to the specified color format.

This is very similar to the `Convert-Bitmap` command, but instead of operating on each pixel in the workbench bitmap, it operates on each color in the workbench palettes. Note that this is almost always faster than `Convert-Bitmap`.

### Deduplicate-Palettes
```
Deduplicate-Palettes [--global/-g]
```

Replaces all duplicate colors in all workbench palettes with new, unique colors.

This command uses a binary search algorithm that runs in `O(m log 2^n)`, where `m` is the number of new colors that need to be generated, and `n` is number of bits in the color space, and is guaranteed to generate unique colors -- as long as the total palette size does not exceed the size of the color space.

The new colors generated by `Deduplicate-Palettes` are random and not guaranteed to be consistent. However, they should be consistent on subsequent runs of the same PixelPet binary.

Normally, color deduplication is applied within each palette individually. However, if the `--global` flag is provided, then deduplication is applied to all palettes as a whole. For instance, if the workbench has two palettes with the exact same color, then with the `--global` flag, one of those colors will be replaced by a new color. The `--global` flag requires that all palettes in the workbench have the same color format.

### Pad-Palettes
```
Pad-Palettes <width> [--color/-c <value>] [--palette-size/-ps <count>]
```

Pads all workbench palettes by adding colors until the palette has at least the specified width.

The `--color` option can be used to specify which color value will be added; by default, this is color value 0.

If there are no palettes in the workbench, a palette is created and filled to the specified width. The `--palette-size` option specifies the maximum size of the palette which is added. If this option is not specified, the maximum size is unbounded.

**Example usage:**
```
Import-Bitmap "input.png"
Extract-Palettes --palette-size 16
Pad-Palettes 16
```
Imports the image `input.png`, extracts palettes from it and then pads all palettes to 16 colors.

### Pad-Tileset
```
Pad-Tileset <width> [--color/-c <value>] [--tile-size/-s <width> <height>]
```

Pads the workbench tileset by adding tiles until the tileset has at least the specified number of tiles.

The `--color` option specifies the color value with which to fill all added tiles. If this is omitted, color value 0 is used.

The `--tile-size` option specifies the size of each tile in pixels. If this is omitted, the tile size of the current tileset will be used. If the current tileset is nonempty, the tile size specified with `--tile-size` must match the tile size of the current tileset.

### Generate-Tilemap
```
Generate-Tilemap <format> [--append/-a] [--no-reduce/-nr] [--x/-x <pixels>] [--y/-y <pixels>] [--width/-w <pixels>] [--height/-h <pixels>] [--tile-size/-s <width> <height>]
```

Generates a tilemap + tileset from the workbench bitmap. The bitmap is processed left-to-right, top-to-bottom.

The `<format>` parameter specifies the tilemap format that is used. This also specifies whether the generated tiles will be indexed. Note that, to generate indexed tiles, the appropriate palettes must first be loaded or extracted.

If `--append` is present, then any new tilemap entries and tiles are appended to the current workbench tilemap and tileset. Otherwise, both the current tilemap and tileset are cleared first.

By default, PixelPet will attempt to reduce the number of tiles in the tileset by eliminating tiles that are already in the tileset, either as-is or flipped horizontally, vertically or in both directions -- provided that the tilemap format supports this. However, you can use the `--no-reduce` option to disable this; if this option is present, PixelPet will add every single tile from the workbench bitmap to the tileset as a new tile.

The `--x`, `--y`, `--width` and `--height` options can be used to process only a portion of the workbench bitmap. The workbench bitmap will not be changed, but it will be processed as if it was cropped using the given parameters, and the first tile begins in the top left corner of the cropped bitmap. By default, the entire workbench bitmap is processed.

The `--tile-size` option specifies the size of each tile in pixels. If this is omitted, the tile size of the current tileset will be used. If the current tileset is nonempty, the tile size specified with `--tile-size` must match the tile size of the current tileset.

**Example usage:**
```
Import-Bitmap "input-256-colors.png"
Extract-Palettes --palette-size 256
Generate-Tilemap GBA-8BPP
```
This imports an image `input-256-colors.png`, extracts a 256-color palette from it, and then uses the palette to generate an optimized tilemap + tileset in the `GBA-8BPP` indexed tilemap format.

### Deserialize-Palettes
```
Deserialize-Palettes <format> [--append/-a] [--palette-number/-pn <number>] [--palette-size/-ps <count>] [--palette-count/-pc <count>] [--offset/-o <count>]
```

Deserializes a series of palettes from the workbench bytestream. `<format>` specifies the color format in which the palettes are stored.

By default this command will read from the start to the end of the bytestream, one unbounded palette. The `--palette-size` option can be used to specify the size of each palette; once the maximum number of colors for the palette has been reached, PixelPet will create a new one, until the end of the bytestream is reached. The `--palette-count` option can be used to set a maximum on the number of palettes, to stop reading earlier.

If `--append` is present, then the new palettes will be added to the current workbench palettes. Otherwise, the current palettes are first discarded.

The `--palette-number` option can be used to specify the initial palette slot number that will be used for any newly created palette. This slot number is increased until an empty slot is found. If this option is not specified, new palettes will get the highest slot number among the loaded palettes + 1.

Finally, the `--offset` option can be used to specify an offset in the bytestream from which to start reading.

**Example usage:**
```
Import-Bytes "rom.gba"
Deserialize-Palettes GBA --palette-size 16 --palette-count 2 --offset 0x600000
```
Imports a ROM `rom.gba`, and reads two 16-color, GBA color format palettes from it at offset `0x600000`.

### Serialize-Palettes
```
Serialize-Palettes [--append/-a]
```

Serializes all palettes currently in the workbench to the workbench bytestream. Each color is serialized in accordance with its current color format; for instance, a 15-bit color palette is serialized as 2 bytes per color. The palettes are serialized in the order that they were added to the workbench.

If `--append` is present, then the serialized palettes are appended to the current workbench bytestream. Otherwise, the current workbench bytestream is discarded first.

### Deserialize-Tileset
```
Deserialize-Tileset <tilemap-format> [--append/-a] [--tile-count/-tc <count>] [--offset/-o <count>] [--tile-size/-s <width> <height>]
```

Deserializes a tileset from the workbench bytestream.

If `--append` is present, then the tiles are added to the existing workbench tileset; otherwise, the current tileset is discarded.

The `<tilemap-format>` parameter specifies the tilemap format that is used. By default this command will begin deserializing from the start of the workbench bytestream until the end; however, the `--offset` option can be used to specify the starting address, and `--tile-count` can be used to specify the number of tiles that should be read. PixelPet will read tiles from the workbench bytestream until the number of tiles specified by `--tile-count` is reached, or the end of the bytestream is reached; whichever comes first.

The `--tile-size` option specifies the size of each tile in pixels. If this is omitted, the tile size of the current tileset will be used. If the current tileset is nonempty, the tile size specified with `--tile-size` must match the tile size of the current tileset.

**Example usage:**
```
Import-Bytes "rom.gba"
Deserialize-Tileset GBA-4BPP --tile-count 0x20 --offset 0x700000
```
Imports a ROM `rom.gba`, and reads 32 (`0x20`) tiles in GBA-4BPP format from offset `0x700000`.

### Serialize-Tileset
```
Serialize-Tileset [--append/a]
```

Serializes the entire workbench tileset to the workbench bytestream. Each tile is serialized in accordance with its current color format; for instance, an 8 by 8 pixels, 4BPP tile is serialized to 32 bytes. The tiles are serialized in the order that they were added to the workbench tileset.

If `--append` is present, the serialized tileset is appended to the end of the workbench bytestream. Otherwise, the previous workbench bytestream is discarded.

### Deserialize-Tilemap
```
Deserialize-Tilemap <tilemap-format> [--append/-a] [--base-tile/-bt <index>] [--tile-count/-tc <count>] [--offset/-o <count>]
```

Deserializes a tilemap from the workbench bytestream.

The `<tilemap-format>` parameter specifies the tilemap format of the serialized tilemap.

If `--append` is present, the tilemap entries are added to the existing workbench tilemap. Otherwise, the workbench tilemap is cleared first.

The `--base-tile` option can be used to specify the tile number that corresponds with the first tile in the tileset. Whichever value is specified for `--base-tile` will be subtracted from the tile numbers referenced in the tilemap as it is being deserialized. By default this is 0.

By default this command begins deserializing from the start of the workbench bytestream, until the end of the bytestream is reached. The `--offset` option can be used to specify the offset in the bytestream from which to begin deserializing. The `--tile-count` option can be used to specify how many tilemap entries should be read; PixelPet will deserialize tilemap entries until the `--tile-count` is reached, or the end of the bytestream is reached; whichever comes first.

**Example usage:**
```
Import-Bytes "rom.gba"
Deserialize-Tilemap --tile-count 600 --offset 0x800000
```
Imports a ROM `rom.gba`, and reads 600 tilemap entries from offset `0x800000`. This could, for instance, correspond to a tilemap which is 30 by 20 tiles large.

### Serialize-Tilemap
```
Serialize-Tilemap [--append/-a] [--base-tile/-bt <index>] [--first-tile/-ft <tilemap-entry>]
```

Serializes the entire workbench tilemap to the workbench bytestream. Currently this command is hardcoded to use the GBA tilemap format.

If `--append` is present, the serialized tilemap is append to the end of the workbench bytestream. Otherwise, the previous workbench bytestream is discarded.

The `--base-tile` option can be used to specify the tile number that corresponds with the first tile in the tileset. Whichever value is specified for `--base-tile` will be added to the tile numbers referenced in the tilemap as it is being serialized. By default this is 0.

The `--first-tile` option can be used to replace any references to the very first tile in the tileset with a fixed value. For instance, one may want to set a `--base-tile` for the tileset but still use tile number 0 for the transparent tile; in this case, the value of the tilemap entry for the first tile can be specified with `--first-tile` directly.

**Example usage:**
```
Import-Bitmap "input-16-colors.png"
Extract-Palettes --palette-size 16
Generate-Tilemap GBA-4BPP
Serialize-Tilemap --base-tile 31 --first-tile 0
```
Imports an image `input-16-colors.png`, generates a 16-color palette from it, generates a tileset + tilemap, then serializes the tilemap whilst adding 31 to all tile numbers and using the value 0 for tilemap entries that reference the first tile.

### Deserialize-Bitmap
```
Deserialize-Bitmap <format> <width> <height> [--offset/-o <count>]
```

Deserializes a bitmap from the workbench bytestream to the workbench bitmap.

The `<format>` parameter specifies the color format in which the bitmap is stored.

The `<width>` and `<height>` parameters specify the width and height of the bitmap in pixels.

By default this command begins deserializing from the start of the workbench bytestream, until a `<width>` times `<height>` pixels are read.. The `--offset` option can be used to specify the offset in the bytestream from which to begin deserializing.

**Example usage:**
```
Import-Bytes "rom.gba"
Deserialize-Bitmap GBA 256 256 --offset 0x800000
```
Imports a ROM `rom.gba`, and deserializes a 256x256 bitmap from offset `0x800000`.

### Serialize-Bitmap
```
Serialize-Bitmap [--append/-a]
```

Serializes the workbench bitmap to the workbench bytestream. The current color format of the workbench bitmap is used.

If `--append` is present, the serialized tilemap is append to the end of the workbench bytestream. Otherwise, the previous workbench bytestream is discarded.

**Example usage:**
```
Import-Bitmap "input.png"
Convert-Bitmap GBA
Serialize-Bitmap
```
Imports a bitmap `input.png`, converts it to GBA colors, then serializes it to the workbench bytestream.

### Apply-Palette-Bitmap
```
Apply-Bitmap-Palette [--palette-number/-pn <number>]
```

Applies a palette to the entire workbench bitmap. For this to work, the workbench bitmap must be in a color format that can be used as palette indices (e.g. 8BPP). After this command finishes, the color indices in the bitmap will have been replaced by the actual colors stored in the palette.

If the `--palette-number` option is specified, the palette with the given number is used. Otherwise, this command will use the palette with the lowest number that has enough colors to be applied to the bitmap.

Only one single palette can be applied to the whole bitmap. In order to use multiple palettes, use `Render-Tileset` or `Render-Tilemap` to render indexed tiles instead.

**Example usage:**
```
Import-Bytes "rom.gba"
Deserialize-Bitmap GBA-4BPP 256 256 0x800000
Deserialize-Palettes GBA --offset 0x700000 --length 0x20
Apply-Palette-Bitmap
```
Imports a ROM `rom.gba`, deserializes a 256x256 4BPP image from `0x800000` and a 16-color palette from `0x700000`, then applies the palette to the bitmap.

### Quantize-Bitmap
```
Quantize-Bitmap <format> [--palette-number/-pn <number>]
```

Quantizes the workbench bitmap using a palette. After this command finishes, all actual colors in the bitmap will have been replaced by color indices used with a palette.

The `<format>` parameter specifies the color format used for the resulting color index pixels. This color format is used when serializing or rendering without palettes loaded. For example, when using a 16-color palette, the resulting pixels will probably be 4BPP.

If the `--palette-number` option is specified, the palette with the given number is used. Otherwise, this command will use the palette with the lowest number that contains all colors used in the bitmap.

**Example usage:**
```
Import-Bytes "rom.gba"
Import-Bitmap "input.png"
Deserialize-Palettes GBA --offset 0x700000 --length 0x20
Quantize-Bitmap GBA-4BPP
```
Imports a ROM `rom.gba` and a bitmap `input.png`, deserializes a 16-color palette from `0x700000`, then quantizes the bitmap to 4BPP using the loaded palette.
